/**
 *	There are some expand string control functions.Based on ANSI C,you can
 *  use gcc to complie them.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <string_ex.h>

 //字符解析函数，根据某个符号将字符进行分割，只适用于ascii的字符
char *
str_segment_character(char delimiter,uint8_t direction,int32_t strnum,char *src)
{
	char *tempsrc;//指向结果字符串的零时指针
	char *tempdeal;//指向临时处理字符串的指针
	char *tempdealdata;//指向临时处理字符串的指针
	int32_t i,j,k;//计数变量
	if(0 == strnum)
		return NULL;//错误处理
	//先来创建一个临时空间装载要处理的字符串
	tempdeal = (char *)malloc(strlen(src) + 1);
	strcpy(tempdeal,src);
	if(LEFT == direction) {//从最左边开始截取的时候
		i = 1;//默认只有一个字符串
		for(j = 0;tempdeal[j] != '\0';j++) {
			//遍历这个字符串
			if(tempdeal[j] == delimiter) {
				//如果找到了分隔符
				i++;
				//表明字符串比原来多了一个（默认为1个字符串）
				if(strnum == i - 1) {
					//返回的字符串一定是给定编号的字符串，在扫描到的分隔符之前
					if(0 == j) {
						free(tempdeal);
						return NULL;
					}
					tempsrc = (char *)malloc(j+1);//创建一个临时字符串空间，包括'\0'
					for(k = 0;k < j;k++)
						tempsrc[k] = tempdeal[k];
					tempsrc[j] = '\0';
					free(tempdeal);//返回前释放空间
					return tempsrc;//返回字符串，分隔结束
				} else {
					//说明这个不是想要的字符串，去掉
					tempdealdata = tempdeal;
					tempdeal = (char *)malloc(strlen(tempdealdata) - j);//为'\0'留位置
					for(j += 1,k = 0;tempdealdata[j] != '\0';j++,k++)
						tempdeal[k] = tempdealdata[j];
					tempdeal[k] = '\0';
					//这里一定要注意一种情况就是以分隔符
					//作为最后一个字符的字符串情况，这里
					//分割后仅剩的字符就没有，最后一个数组
					//就只剩下一个'\0'然后这个本来应该是
					//第0个元素，所以如果j不为-1的话，这里
					//就会自加1变成从1开始找分隔符，明显
					//越界了，千万要注意。
					j = -1;//重新处理
					free(tempdealdata);//释放前面的内存
				}
			}
		}
		if(strnum >= i) {
			if(NULL != tempdeal)
				free(tempdeal);
			return NULL;//错误处理
		} else
			return tempdeal;//表明是最后一个字符串或者没有分隔符
	} else if(RIGHT == direction) {
		//从最右边开始截取
		i = 1;//默认只有一个字符串
		for(j = strlen(tempdeal) - 1;j >= 0;j--) {
			//默认从倒数第一个字母开始，忽略'\0'
			if(tempdeal[j] == delimiter) {
				//如果找到了分隔符
				i++;//表明字符串比原来增加一个
				if(strnum == i - 1 && tempdeal[j + 1] != '\0') {
					//返回的字符串是给定编号的字符串，在扫描到分隔符之前
					int32_t total_size = strlen(tempdeal) - j;
					//创建一个临时字符串空间，包括'\0'
					tempsrc = (char *)malloc(total_size);

					for(k = 0;k < total_size;k++,j++)
						tempsrc[k] = tempdeal[j + 1];
					tempsrc[k - 1] = '\0';
					free(tempdeal);//返回前释放空间
					return tempsrc;//返回字符串，分隔结束
				} else {
					//说明这个不是想要的字符串，去掉
					tempdealdata = tempdeal;
					tempdeal = (char *)malloc(j + 1);//'\0'要留位置
					strncpy(tempdeal,tempdealdata,j);
					tempdeal[j] = '\0';
					//j = strlen(tempdeal);//重新处理字符串
					free(tempdealdata);// 释放前面的内存
				}
			}
		}
		//注意i的取值，遍历完成的时候i一定比最后一个编号大1
		if(strnum >= i) {
			if(NULL != tempdeal)
				free(tempdeal);
			return NULL;//错误处理
		} else {
			if('\0' == tempdeal[0]) {//说明开头或者结尾是分割符
				free(tempdeal);
				return NULL;
			}
			return tempdeal;//表明是最后一个字符串或者没有分隔符
		}
	} else
		return NULL;//参数错误处理
}

//字符串分隔函数，相对于上面的函数更加的快
str_seg_elem *
str_segment_character_fast(char delimiter,uint8_t direction,const char *src)
{
	char *tempdeal;//待处理的字符串
	char *tempsrc;//处理得出的结果字符串
	char *tempdealdata;//临时字符串
	int32_t i,j;//计数器变量
	if(NULL == src)
	 return NULL;
	tempdeal = (char *)malloc(strlen(src) + 1);
	strcpy(tempdeal,src);//将资源进行拷贝
	//sl_node *dealHead;
	//SingleListInitiate(&dealHead);
	//初始化一个链表
	str_seg_elem *dealHead = \
		 (str_seg_elem *)malloc(sizeof(str_seg_elem));
	dealHead->node = NULL;
	dealHead->word_seg = NULL;
	switch(direction)
	{
	case LEFT://使用绝对尾插法
		for(i = 0;'\0' != tempdeal[i];i++) {
			if(delimiter == tempdeal[i]) {
				//找到分隔符
				tempsrc = (char *)malloc(i + 1);
				for(j = 0;j < i;j++)
					tempsrc[j] = tempdeal[j];
				tempsrc[i] = '\0';
				//插入到链表当中
				if(0 != i) {//这里要将分割到的字符串插入链表
					if(NULL == dealHead->word_seg)
						dealHead->word_seg = tempsrc;
					else {
						str_seg_elem *new = \
							 (str_seg_elem *)malloc(sizeof(str_seg_elem));
						new->node = NULL;
						new->word_seg = tempsrc;
						sl_insert_tail_absolute(dealHead,new);
					}
				} else
					free(tempsrc);//不需要的就要立刻释放
				//删除分隔符之前的字符串
				tempdealdata = (char *)malloc(strlen(tempdeal) - strlen(tempsrc));
				i += 1;
				for(j = 0;'\0' != tempdeal[i];j++,i++)
					tempdealdata[j] = tempdeal[i];
				tempdealdata[j] = '\0';
				free(tempdeal);
				tempdeal = tempdealdata;
				i = -1;
			}
		}
		//最后一个字符串在这里插入
		if('\0' != tempdeal[0]) {
			str_seg_elem *left_new = \
				 (str_seg_elem *)malloc(sizeof(str_seg_elem));
			left_new->node = NULL;
			left_new->word_seg = tempdeal;
			sl_insert_tail_absolute(dealHead,left_new);
		} else
			free(tempdeal);//不能插入链表就要释放
		//其实不用释放了字符串都应该被链表接收了
		//如果分隔符是最后一个字符，那么这里最后
		//一个字符串的插入就只有长度为1且是'\0'
		return dealHead;
	case RIGHT://使用绝对头插法
		for(i = 0;'\0' != tempdeal[i];i++) {
			if(delimiter == tempdeal[i]) {//找到分隔符
				tempsrc = (char *)malloc(i + 1);
				for(j = 0;j < i;j++)
					tempsrc[j] = tempdeal[j];
				tempsrc[i] = '\0';
				//插入到链表当中
				if(0 != i) {
					if(NULL == dealHead->word_seg)
						dealHead->word_seg = tempsrc;
					else {
						str_seg_elem *new = \
							 (str_seg_elem *)malloc(sizeof(str_seg_elem));
						new->node = NULL;
						new->word_seg = tempsrc;
						sl_insert_head_absolute(dealHead,new);
					}
				} else
					free(tempsrc);
				//删除分隔符之前的字符串
				tempdealdata = (char *)malloc(strlen(tempdeal) - strlen(tempsrc));
				i += 1;
				for(j = 0;'\0' != tempdeal[i];j++,i++)
					tempdealdata[j] = tempdeal[i];
				tempdealdata[j] = '\0';
				free(tempdeal);
				tempdeal = tempdealdata;
				i = -1;
			}
		}
		//最后一个字符串在这里插入
		if('\0' != tempdeal[0]) {
			str_seg_elem *right_new = \
				 (str_seg_elem *)malloc(sizeof(str_seg_elem));
			right_new->node = NULL;
			right_new->word_seg = tempdeal;
			sl_insert_head_absolute_fast(dealHead,right_new);
		} else
			free(tempdeal);//不能插入就要释放
		return dealHead;
	default:
		return NULL;
	}
}

 //字符串分割函数的链表版本的链表销毁函数
bool
str_segment_character_list_destroy(str_seg_elem *str_list)
{
	if(NULL == str_list)
		return false;
	//进行链表销毁操作
	str_seg_elem *tmp = str_list;
	while(NULL != tmp) {
		if(NULL != tmp->word_seg)
			free(tmp->word_seg);
		str_list = tmp->node;
		free(tmp);
		tmp = str_list;
	}
	return true;
}

//宽字符版本的字符分割函数（暂不实现）

//判断输入的字符串是否是一串数字组成的
bool
is_str_digit(const char *src)
{
	while(*src != '\0') {
		if(!(*src >= '0' && *src <= '9'))
			return false;
		src++;
	}
	return true;
}

//将一个16进制数（0-f）转化为整形
static int32_t
hex(char *hex_num)
{
	if(hex_num[0] <= '9' && hex_num[0] >= '0')
		return atoi(hex_num);
	else if(hex_num[0] <= 'f' && hex_num[0] >= 'a')
		return (hex_num[0] - 87);
	else if(hex_num[0] <= 'F' && hex_num[0] >= 'A')
		return (hex_num[0] - 55);
	else
		return 0;
}

int32_t
atoi_sint32_ex(char *num_str)
{
	//检测第一个字符
	if('0' == num_str[0]) {
		int32_t i,temp = 0;
		char num_temp[2];
		//可能是二进制、八进制、十六进制
		if('b' == num_str[1] || 'B' == num_str[1]) {
			//二进制
			if(strlen(num_str) > 34)//最大只转换31位的二进制表示，最高位1表示正负
				return 0;
			for(i = ((strlen(num_str) == 34) ? 3 : 2);'\0' != num_str[i];i++) {
				if('0' != num_str[i] && '1' != num_str[i])
					return 0;
				else {
					num_temp[0] = num_str[i];
					num_temp[1] = '\0';
					temp += atoi(num_temp) * pow(2,strlen(num_str) - (i + 1));
				}
			}
			return ((strlen(num_str) == 34) && num_str[2] == '1') ? \
					-((~temp & 0x7fffffff) + 1) : temp;
		} else if('x' == num_str[1] || 'X' == num_str[1]) {
			//十六进制
			//最大只支持到31位，最高位表示正负。0x7fffffff是最大
			if(strlen(num_str) > 10)
				return 0;
			else if(10 == strlen(num_str)) {
				num_temp[0] = num_str[2];
				num_temp[1] = '\0';
				temp = (hex(num_temp) & 0x7) * pow(16,7);
				for(i = 3;'\0' != num_str[i];i++) {
					num_temp[0] = num_str[i];
					num_temp[1] = '\0';
					temp += hex(num_temp) *  pow(16,strlen(num_str) - (i + 1));
				}
				num_temp[0] = num_str[2];
				num_temp[1] = '\0';
				return ((hex(num_temp) & 0x8) ? -((~temp & 0x7fffffff) + 1) : temp);
			} else {
				for(i = 2;'\0' != num_str[i];i++) {
					num_temp[0] = num_str[i];
					num_temp[1] = '\0';
					temp += hex(num_temp) * pow(16,strlen(num_str) - (i + 1));
				}
				return temp;
			}
		} else {
			//八进制
			//最大31位，最高位表示正负
			if(strlen(num_str) > 12)
				return 0;
			else if(strlen(num_str) == 12) {
				num_temp[0] = num_str[1];
				num_temp[1] = '\0';
				temp = (atoi(num_temp) & 0x1) * pow(8,10);
				for(i = 2;'\0' != num_str[i];i++) {
					num_temp[0] = num_str[i];
					num_temp[1] = '\0';
					temp += atoi(num_temp) * pow(8,strlen(num_str) - (i + 1));
				}
				num_temp[0] = num_str[1];
				num_temp[1] = '\0';
				return (atoi(num_temp) & 2) ? -((~temp & 0x7fffffff) + 1) : temp;
			} else {
				for(i = 1;'\0' != num_str[i];i++) {
					num_temp[0] = num_str[i];
					num_temp[1] = '\0';
					if(atoi(num_temp) > 7)
						return 0;
					temp += atoi(num_temp) * pow(8,strlen(num_str) - (i + 1));
				}
				return temp;
			}
		}
	} else
		return atoi(num_str);
}

//字符串模糊匹配算法
//两个字符串相同长度，且相同位置字符相同的个数和总的字符个数相比达到给定的模糊度就认为匹配
//match_persent越低，字符串就越容易匹配
int32_t
str_cmp_ex(const char *dest1,const char *dest2,const double match_persent)
{
	int dismatchnum = 0;
	const char *dest1_temp = dest1;
	while('\0' != *dest1 && '\0' != *dest2) {
		if(*dest1 == *dest2)
			dismatchnum++;
		dest1++;
		dest2++;
	}
	if('\0' != *dest1 && '\0' == *dest2)//dest1 < dest2
		return -1;
	if('\0' == *dest1 && '\0' != *dest2)//dest1 > dest2
		return 1;
	if('\0' == *dest1 && '\0' == *dest2) {
		//dest1 == dest2
		if(match_persent <= (double)(dismatchnum)/(double)(strlen(dest1_temp)))
			return 0;
	}
	return -2;
}
